import { Node } from "@rivet/model";
import { Step, StepResult } from "./step.ts";
import type { Draft } from "immer";

//自定义
export class TrStep extends Step {
  constructor(changes: any[], inverseChanges: any[]) {
    super();
    this.changes = changes;
    this.inverse = inverseChanges;
  }
  apply(_draft: any, _doc: Node) {
    return undefined;
  }
}
//根据id修改node的attrs
export class AttrStep extends Step {
  id: string;
  value: any;

  constructor(
    id: string,
    value: any,
  ) {
    super();
    this.id = id;

    this.value = value;
  }

  apply(draft: Draft<Node> | null, doc: Node): StepResult | undefined {
    const node = doc.nodeAt(this.id);
    if (!node) return StepResult.fail("id 对应的节点不存在");
    if (draft) {
      Node.setAttrs(draft, this.id, this.value);
      return;
    }
    return StepResult.fromReplace(doc, (draftState) => {
      Node.setAttrs(draftState, this.id, this.value);
    }, (patches, inversePatches) => {
      this.changes.push(...patches);
      this.inverse.push(...inversePatches);
    });
  }
}
Step.jsonID("attr", AttrStep);

function modifyStateAndForPath(draft: Draft<Node>, path: string[], value: any) {
  let current: any = draft;
  for (let i = 0; i < path.length - 1; i++) {
    current = current[path[i]];
  }
  current[path[path.length - 1]] = value;
}
/*
根据path修改state
*/
export class AttrPathStep extends Step {
  path: string[];
  value: any;

  constructor(
    value: any,
    path: string[],
  ) {
    super();
    this.path = path;
    this.value = value;
  }
  apply(draft: Draft<Node> | null, doc: Node): StepResult | undefined {
    let current: any = doc;
    for (let i = 0; i < this.path.length - 1; i++) {
      current = current[this.path[i]];
      if (!current) return StepResult.fail("id 对应的节点不存在");
    }
    if (draft) {
      modifyStateAndForPath(draft, this.path, this.value);
      return;
    }
    return StepResult.fromReplace(doc, (draftState) => {
      modifyStateAndForPath(draftState, this.path, this.value);
    }, (patches, inversePatches) => {
      this.changes.push(...patches);
      this.inverse.push(...inversePatches);
    });
  }
}
Step.jsonID("attrpathstep", AttrPathStep);
